#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include "MPX_SUPT.h"
#include "pcb.h"
#include "R3.h"
#include "procs-r3.h"
#include "R2.h"

pcb *to_run;
unsigned short ss_save = NULL;
unsigned short sp_save = NULL;
unsigned short new_ss;
unsigned short new_sp;
unsigned long stack_top;
unsigned char sys_stack[SYS_STACK_SIZE];

params *this_param = NULL;

void interrupt dispatch(){ //NO VARIABLES EXCEPT FOR STATIC
	
	//save SS and SP only once
	if(sp_save == NULL) {
		ss_save = _SS;
		sp_save = _SP;
	}
	//get head of ready queue, if it exists
	to_run = get_ready_head();
	if(to_run != NULL){
		//remove pcb and set to running
		remove_pcb(to_run);
		to_run->state = PROC_STATE_RUNNING;
		//set SP to top of pcb stack
		new_ss = FP_SEG(to_run->stack_top);
		new_sp = FP_OFF(to_run->stack_top);
		_SS = new_ss;
		_SP = new_sp;
	}
	else{
		to_run = NULL;
		_SS = ss_save;
		_SP = sp_save;
		ss_save = NULL;
		sp_save = NULL;
	}
}

void interrupt sys_call(){ //NO VARIABLES EXCEPT FOR STATIC
	//1) you must save the SS & SP back into stack top
	to_run->stack_top = (unsigned char*) MK_FP(_SS, _SP);
	//2) switch to a temporaary stack
	
	//save SS and SP
	this_param = (params*)(to_run->stack_top + sizeof(context));
	//change to temp stack
	if(this_param->op_code == IDLE){
		to_run->state = PROC_STATE_READY;
		insert_pcb(to_run, PROC_STATE_READY, PROC_NOT_SUSP);
	}
	else if(this_param->op_code == EXIT){
		free_pcb(to_run);
		to_run = NULL;
	}
	
	dispatch();
}

void load_procs(){
	pcb *np;
	context *npc;
	np = setup_PCB("name1", 1, 0);
	if(np != NULL){
		npc = (context*) np->stack_top; //notes say stack_top
		npc->IP = FP_OFF(&test1_R3);
		npc->CS = FP_SEG(&test1_R3);
		npc->FLAGS = 0x200;
		npc->DS = _DS;
		npc->ES = _ES;
		insert_pcb(np, PROC_STATE_READY, PROC_NOT_SUSP);
	}
	
	np = setup_PCB("name2", 1, 0);
	if(np != NULL){
		npc = (context*) np->stack_top; //notes say stack_top
		npc->IP = FP_OFF(&test2_R3);
		npc->CS = FP_SEG(&test2_R3);
		npc->FLAGS = 0x200;
		npc->DS = _DS;
		npc->ES = _ES;
		insert_pcb(np, PROC_STATE_READY, PROC_NOT_SUSP);
	}
	
	np = setup_PCB("name3", 1, 0);
	if(np != NULL){
		npc = (context*) np->stack_top; //notes say stack_top
		npc->IP = FP_OFF(&test3_R3);
		npc->CS = FP_SEG(&test3_R3);
		npc->FLAGS = 0x200;
		npc->DS = _DS;
		npc->ES = _ES;
		insert_pcb(np, PROC_STATE_READY, PROC_NOT_SUSP);
	}
	
	np = setup_PCB("name4", 1, 0);
	if(np != NULL){
		npc = (context*) np->stack_top; //notes say stack_top
		npc->IP = FP_OFF(&test4_R3);
		npc->CS = FP_SEG(&test4_R3);
		npc->FLAGS = 0x200;
		npc->DS = _DS;
		npc->ES = _ES;
		insert_pcb(np, PROC_STATE_READY, PROC_NOT_SUSP);
	}
	
	np = setup_PCB("name5", 1, 0);
	if(np != NULL){
		npc = (context*) np->stack_top; //notes say stack_top
		npc->IP = FP_OFF(&test5_R3);
		npc->CS = FP_SEG(&test5_R3);
		npc->FLAGS = 0x200;
		npc->DS = _DS;
		npc->ES = _ES;
		insert_pcb(np, PROC_STATE_READY, PROC_NOT_SUSP);
	}
}